{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. 项目描述："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "企业的快速发展离不开人才的支撑，可是现在我国的企业的人才流失严重，人才流失问题现在已经成为了关系企业发展的一个重大的问题。这些企业要想在目前激烈的竞争中快速发展，就需要依靠自身的人力资源的来竞争。只有拥有比对方更强，更优秀，更具有创造力的人才，才能在竞争中取得优势。所以如何有效解决我国企业人才流失问题是一个很迫切的任务。人才流失已经成了很多企业正在面临的困境，关键人才的流程对企业的影响尤为明显。\t无论在IT互联网领域还是传统领域、事业单位，均面临关键人才的流失，作为公司的核心的人力资源部门，我们需要把控员工的基本情况，对员工的情况进行实时监控和预测，人才流失模型从公司的角度和员工自身角度分别入手，阐释了在那些重要维度能够保持流失率的下降，常规的做法比如增强企业文化，提高薪资，提高年终奖等，通过模型给出人力资源部门一定的建议。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. 技术说明："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "项目通过公司内部人资资源系统数据，通过数据的基本ETL(数据清洗过滤和汇总)对数据进行基本的预处理，通过python的numpy、pandas、matplotlib和seaborn进行各维度数据分析，经过数据分析得到分类特征较好的特征数据，对数值型数据、类别型数据、有序性数据分别进行处理和分析，使用label encoder和one encoder分别对类别数据进行特征编码，处理组合后的数据特征后形成特征向量，通过Python的Scikit-learn机器学习库的机器学习算法寻找数据之间存在的关系，从而为公司人力资源及决策层提供信息建议及决策建议。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. 需求分析："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "1 分析各个维度的数据对人才流失的影响\n",
    "\n",
    "2 通过训练数据建立的模型以及所给的测试数据，构建人才流失模型，最终预测测试数据相应的员工是否已经离职（0未离职，1离职）。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4. 数据集描述:\n",
    "\n",
    "数据主要包括影响员工离职的各种因素（工资、出差、工作环境满意度、工作投入度、是否加班、是否升职、工资提升比例等）以及员工是否已经离职的对应记录。数据分为训练数据和测试数据，分别保存在train.csv和test.csv两个文件中。训练数据主要包括1100条记录，31个字段。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Attrition：员工是否已经离职，1表示已经离职，0表示未离职，这是目标预测值；\n",
    "* Age：员工年龄\n",
    "* BusinessTravel：商务差旅频率，Non-Travel表示不出差，Travel_Rarely表示不经常出差，Travel_Frequently表示经常出差；\n",
    "* Department：员工所在部门，Sales表示销售部，Research & Development表示研发部，Human Resources表示人力资源部；\n",
    "* DistanceFromHome：公司跟家庭住址的距离，从1到29，1表示最近，29表示最远；\n",
    "* Education：员工的教育程度，从1到5，5表示教育程度最高；\n",
    "* EducationField：员工所学习的专业领域，Life Sciences表示生命科学，Medical表示医疗，Marketing表示市场营销，Technical Degree表示技术学位，Human Resources表示人力资源，Other表示其他；\n",
    "* EmployeeNumber：员工号码；\n",
    "* EnvironmentSatisfaction：员工对于工作环境的满意程度，从1到4，1的满意程度最低，4的满意程度最高；\n",
    "* Gender：员工性别，Male表示男性，Female表示女性；\n",
    "* JobInvolvement：员工工作投入度，从1到4，1为投入度最低，4为投入度最高；\n",
    "* JobLevel：职业级别，从1到5，1为最低级别，5为最高级别；\n",
    "* JobRole：工作角色：Sales Executive是销售主管，Research Scientist是科学研究员，Laboratory Technician实验室技术员，Manufacturing Director是制造总监，Healthcare Representative是医疗代表，Manager是经理，Sales Representative是销售代表，Research Director是研究总监，Human Resources是人力资源；\n",
    "* JobSatisfaction：工作满意度，从1到4，1代表满意程度最低，4代表满意程度最高；\n",
    "* MaritalStatus：员工婚姻状况，Single代表单身，Married代表已婚，Divorced代表离婚；\n",
    "* MonthlyIncome：员工月收入，范围在1009到19999之间；\n",
    "* NumCompaniesWorked：员工曾经工作过的公司数；\n",
    "* Over18：年龄是否超过18岁；\n",
    "* OverTime：是否加班，Yes表示加班，No表示不加班；\n",
    "* PercentSalaryHike：工资提高的百分比；\n",
    "* PerformanceRating：绩效评估；\n",
    "* RelationshipSatisfaction：关系满意度，从1到4，1表示满意度最低，4表示满意度最高；\n",
    "* StandardHours：标准工时；\n",
    "* StockOptionLevel：股票期权水平；\n",
    "* TotalWorkingYears：总工龄；\n",
    "* TrainingTimesLastYear：上一年的培训时长，从0到6，0表示没有培训，6表示培训时间最长；\n",
    "* WorkLifeBalance：工作与生活平衡程度，从1到4，1表示平衡程度最低，4表示平衡程度最高；\n",
    "* YearsAtCompany：在目前公司工作年数；\n",
    "* YearsInCurrentRole：在目前工作职责的工作年数\n",
    "* YearsSinceLastPromotion：距离上次升职时长\n",
    "* YearsWithCurrManager：跟目前的管理者共事年数；"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5. 流程分析"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 数据获取(来源于公司内部的人力资源数据，通常没有缺失值的)\n",
    "2. 数据探索性分析\n",
    "3. 数据预处理\n",
    "4. 特征处理\n",
    "5. 数据集的划分：使用20%部分作为测试集，80%作为训练集\n",
    "6. 模型训练：逻辑回归、决策树、随机森林等\n",
    "7. 模型校验：模型准确率、召回率、精确率、F1值、ROC曲线(横轴：真正率TRP，纵轴：假正率FPR)-----通过曲线和x轴围城的面积衡量分类性能的好坏，曲线面积叫做AUC值---面积大小代表准确率大小---Roc-Auc曲线\n",
    "8. 使用imblearn框架进一步采样过采样或欠采样或结合方式或集成采样方式对\n",
    "9. 类别不均衡的问题进一步处理\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 6. 代码实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-07T07:03:32.484459Z",
     "start_time": "2025-06-07T07:03:32.480799Z"
    }
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-07T07:03:32.492372Z",
     "start_time": "2025-06-07T07:03:32.485920Z"
    }
   },
   "outputs": [],
   "source": [
    "# 读取CSV文件（内存优化关键步骤）\n",
    "# 使用低内存模式并指定数据类型（基于Evidence 7/17/20）\n",
    "dtypes = {   \n",
    "    'YearsWithCurrManager': 'float32',  \n",
    "    'YearsAtCompany': 'float32',  \n",
    "    'JobSatisfaction': 'float32',\n",
    "    'EnvironmentSatisfaction': 'float32',\n",
    "    'RelationshipSatisfaction': 'float32',\n",
    "    'WorkLifeBalance': 'float32',\n",
    "    'JobInvolvement': 'float32',\n",
    "    'JobSatisfaction': 'float32',\n",
    "    'NumCompaniesWorked': 'float32' \n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-07T07:04:40.177892Z",
     "start_time": "2025-06-07T07:04:40.096579Z"
    }
   },
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "[Errno 2] No such file or directory: '../data/train.csv'",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mFileNotFoundError\u001B[0m                         Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[4], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m df \u001B[38;5;241m=\u001B[39m pd\u001B[38;5;241m.\u001B[39mread_csv(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m../data/train.csv\u001B[39m\u001B[38;5;124m'\u001B[39m, \n\u001B[0;32m      2\u001B[0m                  encoding\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mutf-8\u001B[39m\u001B[38;5;124m'\u001B[39m,  \u001B[38;5;66;03m# 处理特殊字符（Evidence 3）\u001B[39;00m\n\u001B[0;32m      3\u001B[0m                  dtype\u001B[38;5;241m=\u001B[39mdtypes,           \u001B[38;5;66;03m# 优化内存（Evidence 7）\u001B[39;00m\n\u001B[0;32m      4\u001B[0m                  usecols\u001B[38;5;241m=\u001B[39m[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mYearsWithCurrManager\u001B[39m\u001B[38;5;124m'\u001B[39m,\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mYearsAtCompany\u001B[39m\u001B[38;5;124m'\u001B[39m,\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mJobSatisfaction\u001B[39m\u001B[38;5;124m'\u001B[39m,\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mEnvironmentSatisfaction\u001B[39m\u001B[38;5;124m'\u001B[39m,\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mRelationshipSatisfaction\u001B[39m\u001B[38;5;124m'\u001B[39m,\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mWorkLifeBalance\u001B[39m\u001B[38;5;124m'\u001B[39m,\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mJobInvolvement\u001B[39m\u001B[38;5;124m'\u001B[39m,\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mJobSatisfaction\u001B[39m\u001B[38;5;124m'\u001B[39m,\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mNumCompaniesWorked\u001B[39m\u001B[38;5;124m'\u001B[39m],\u001B[38;5;66;03m# 只加载必要列（Evidence 20）\u001B[39;00m\n\u001B[0;32m      5\u001B[0m                  engine\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mc\u001B[39m\u001B[38;5;124m'\u001B[39m)\n",
      "File \u001B[1;32mD:\\anaconda\\Lib\\site-packages\\pandas\\io\\parsers\\readers.py:1026\u001B[0m, in \u001B[0;36mread_csv\u001B[1;34m(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend)\u001B[0m\n\u001B[0;32m   1013\u001B[0m kwds_defaults \u001B[38;5;241m=\u001B[39m _refine_defaults_read(\n\u001B[0;32m   1014\u001B[0m     dialect,\n\u001B[0;32m   1015\u001B[0m     delimiter,\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m   1022\u001B[0m     dtype_backend\u001B[38;5;241m=\u001B[39mdtype_backend,\n\u001B[0;32m   1023\u001B[0m )\n\u001B[0;32m   1024\u001B[0m kwds\u001B[38;5;241m.\u001B[39mupdate(kwds_defaults)\n\u001B[1;32m-> 1026\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m _read(filepath_or_buffer, kwds)\n",
      "File \u001B[1;32mD:\\anaconda\\Lib\\site-packages\\pandas\\io\\parsers\\readers.py:620\u001B[0m, in \u001B[0;36m_read\u001B[1;34m(filepath_or_buffer, kwds)\u001B[0m\n\u001B[0;32m    617\u001B[0m _validate_names(kwds\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mnames\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mNone\u001B[39;00m))\n\u001B[0;32m    619\u001B[0m \u001B[38;5;66;03m# Create the parser.\u001B[39;00m\n\u001B[1;32m--> 620\u001B[0m parser \u001B[38;5;241m=\u001B[39m TextFileReader(filepath_or_buffer, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwds)\n\u001B[0;32m    622\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m chunksize \u001B[38;5;129;01mor\u001B[39;00m iterator:\n\u001B[0;32m    623\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m parser\n",
      "File \u001B[1;32mD:\\anaconda\\Lib\\site-packages\\pandas\\io\\parsers\\readers.py:1620\u001B[0m, in \u001B[0;36mTextFileReader.__init__\u001B[1;34m(self, f, engine, **kwds)\u001B[0m\n\u001B[0;32m   1617\u001B[0m     \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39moptions[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mhas_index_names\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m kwds[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mhas_index_names\u001B[39m\u001B[38;5;124m\"\u001B[39m]\n\u001B[0;32m   1619\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhandles: IOHandles \u001B[38;5;241m|\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[1;32m-> 1620\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_engine \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_make_engine(f, \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mengine)\n",
      "File \u001B[1;32mD:\\anaconda\\Lib\\site-packages\\pandas\\io\\parsers\\readers.py:1880\u001B[0m, in \u001B[0;36mTextFileReader._make_engine\u001B[1;34m(self, f, engine)\u001B[0m\n\u001B[0;32m   1878\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mb\u001B[39m\u001B[38;5;124m\"\u001B[39m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;129;01min\u001B[39;00m mode:\n\u001B[0;32m   1879\u001B[0m         mode \u001B[38;5;241m+\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mb\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[1;32m-> 1880\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhandles \u001B[38;5;241m=\u001B[39m get_handle(\n\u001B[0;32m   1881\u001B[0m     f,\n\u001B[0;32m   1882\u001B[0m     mode,\n\u001B[0;32m   1883\u001B[0m     encoding\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39moptions\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mencoding\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mNone\u001B[39;00m),\n\u001B[0;32m   1884\u001B[0m     compression\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39moptions\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mcompression\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mNone\u001B[39;00m),\n\u001B[0;32m   1885\u001B[0m     memory_map\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39moptions\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmemory_map\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mFalse\u001B[39;00m),\n\u001B[0;32m   1886\u001B[0m     is_text\u001B[38;5;241m=\u001B[39mis_text,\n\u001B[0;32m   1887\u001B[0m     errors\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39moptions\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mencoding_errors\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mstrict\u001B[39m\u001B[38;5;124m\"\u001B[39m),\n\u001B[0;32m   1888\u001B[0m     storage_options\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39moptions\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mstorage_options\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mNone\u001B[39;00m),\n\u001B[0;32m   1889\u001B[0m )\n\u001B[0;32m   1890\u001B[0m \u001B[38;5;28;01massert\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhandles \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[0;32m   1891\u001B[0m f \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mhandles\u001B[38;5;241m.\u001B[39mhandle\n",
      "File \u001B[1;32mD:\\anaconda\\Lib\\site-packages\\pandas\\io\\common.py:882\u001B[0m, in \u001B[0;36mget_handle\u001B[1;34m(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)\u001B[0m\n\u001B[0;32m    873\u001B[0m         handle \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mopen\u001B[39m(\n\u001B[0;32m    874\u001B[0m             handle,\n\u001B[0;32m    875\u001B[0m             ioargs\u001B[38;5;241m.\u001B[39mmode,\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m    878\u001B[0m             newline\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[0;32m    879\u001B[0m         )\n\u001B[0;32m    880\u001B[0m     \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m    881\u001B[0m         \u001B[38;5;66;03m# Binary mode\u001B[39;00m\n\u001B[1;32m--> 882\u001B[0m         handle \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mopen\u001B[39m(handle, ioargs\u001B[38;5;241m.\u001B[39mmode)\n\u001B[0;32m    883\u001B[0m     handles\u001B[38;5;241m.\u001B[39mappend(handle)\n\u001B[0;32m    885\u001B[0m \u001B[38;5;66;03m# Convert BytesIO or file objects passed with an encoding\u001B[39;00m\n",
      "\u001B[1;31mFileNotFoundError\u001B[0m: [Errno 2] No such file or directory: '../data/train.csv'"
     ]
    }
   ],
   "source": [
    "df = pd.read_csv('../data/train.csv', \n",
    "                 encoding='utf-8',  # 处理特殊字符（Evidence 3）\n",
    "                 dtype=dtypes,           # 优化内存（Evidence 7）\n",
    "                 usecols=['YearsWithCurrManager','YearsAtCompany','JobSatisfaction','EnvironmentSatisfaction','RelationshipSatisfaction','WorkLifeBalance','JobInvolvement','JobSatisfaction','NumCompaniesWorked'],# 只加载必要列（Evidence 20）\n",
    "                 engine='c')             # 使用C引擎加快读取速度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "start_time": "2025-06-07T07:03:33.307003Z"
    }
   },
   "outputs": [],
   "source": [
    "df.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算经理稳定性（与当前经理共事年限/在公司工作年限）。\n",
    "df['ManagerStability'] = df['YearsWithCurrManager'].div(df['YearsAtCompany']+0.001)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "start_time": "2025-06-07T07:03:33.308030Z"
    }
   },
   "outputs": [],
   "source": [
    "# 计算综合满意度（工作满意度×0.3 + 工作环境满意度×0.2 + 人际关系满意度×0.2 + 工作生活平衡度×0.15 + 工作投入度×0.15）\n",
    "df['JobSatisfactionScore'] = (df['JobSatisfaction'] * 0.3 + \n",
    "                  df['EnvironmentSatisfaction'] * 0.2 + \n",
    "                  df['RelationshipSatisfaction'] * 0.2 + \n",
    "                  df['WorkLifeBalance'] * 0.15 + \n",
    "                  df['JobInvolvement'] * 0.15)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算员工稳定性（工作满意度/（呆过公司数量+））\n",
    "df['EmployeeStability'] = (df['JobSatisfaction'] / df['NumCompaniesWorked']+1)\n",
    "df.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "start_time": "2025-06-07T07:03:33.309495Z"
    }
   },
   "outputs": [],
   "source": [
    "df['ResourceSatisfaction'] = (df['EnvironmentSatisfaction'] +df['RelationshipSa3tisfaction']) / 2\n",
    "df.info()"
   ]
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "df['CareerStagnation'] = df['YearsSinceLastPromotion'] / (df['YearsAtCompany'] + 0.001)\n",
    "df.info()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2025-06-07T07:03:33.310973Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "start_time": "2025-06-07T07:03:33.310973Z"
    }
   },
   "outputs": [],
   "source": [
    "# 提取features\n",
    "selected_features = df[['ManagerStability', 'JobSatisfactionScore','EmployeeStability',  'ResourceSatisfaction', 'CareerStagnation']]\n",
    "selected_features\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "ai_test",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
